//! \file GUI.cpp
//! \brief TODO: Document
// -----------------------------------------------------------------------------
//! This program is free software; you can redistribute it and/or
//! modify it under the terms of the GNU General Public License
//! as published by the Free Software Foundation; either version 2
//! of the License, or (at your option) any later version.
//!
//! This program is distributed in the hope that it will be useful,
//! but WITHOUT ANY WARRANTY; without even the implied warranty of
//! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//! GNU General Public License for more details.
//!
//! You should have received a copy of the GNU General Public License
//! along with this program; if not, write to the Free Software Foundation,
//! Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// -----------------------------------------------------------------------------

#include "Gui.h"

//#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <CEGUI.h>
#include <CEGUI/RendererModules/OpenGL/CEGUIOpenGLRenderer.h>
//#include <CEGUIDefaultResourceProvider.h>
//using namespace CEGUI;

// =====[ Local Definitions ]===================================================

// =====[ Local DataTypes ]=====================================================

// =====[ Local Variables ]=====================================================

  // SDL
SDL_Surface *GUI::m_pSurface = NULL;

  // CEGUI
CEGUI::WindowManager *GUI::m_pWm = NULL;
// static CEGUI::System *d_system;       // the gui system
CEGUI::Window *GUI::m_pRoot = NULL;
CEGUI::Font *GUI::m_pFont = NULL;

// =====[ Local Functions ]=====================================================

// =====[ Private (Internal) Methods ]==========================================

// =====[ Local Implementation ]================================================


// =====[ Public Methods ]======================================================


// =============================================================================
// GUI::Start
// -----------------------------------------------------------------------------
//! TODO: document This starts the GUI to operate.
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::Start(void)
{
  tERROR Error;

  Error = InitSDL(); // TODO: check for errors
  Error = InitOpenGL(); // TODO: check for errors
  Error = InitCEGUI(); // TODO: check for errors.



  Error = NewMenuMain(NULL);
  Error = NewWindowConsole(NULL);

  // TODO: fork the thread


  // TODO: create a thread and return?

//  using namespace CEGUI;

  // -------------------- CREATE THE ROOT "WINDOW"
//  using namespace CEGUI;



  // Finally, return success.
  return (dNO_ERROR);
}


// =============================================================================
// GUI::Stop
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::Stop(tERROR Error)
{
  // TODO: implement function
  return (Error);
}



//void render_gui()
//{
//  /* clear the colour buffer */
//  glClear( GL_COLOR_BUFFER_BIT );
//
//  GUI::DisplayTask(NULL);
//
//  /* render the GUI :) */
//  CEGUI::System::getSingleton().renderGUI();
//
//  /* Update the screen */
//  SDL_GL_SwapBuffers();
//}


// =====[ Private Methods ]=====================================================


// =============================================================================
// GUI::InitSDL
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::InitSDL(void)
{
//  atexit() // TODO

  // Initialize SDL.
  if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
    { return (Stop(dERROR_UI_DISPLAY_FAILED_TO_START)); }

  // Create our SDL drawing surface.
  m_pSurface = SDL_SetVideoMode(800, 600, 0, SDL_OPENGL);
  if (m_pSurface == NULL)
    { return (Stop(dERROR_SDL_SURFACE_CREATION)); }

  // Configure SDL to play nice with our OpenGL host.
  SDL_ShowCursor(SDL_DISABLE);                  // Hide the SDL cursor.
  SDL_EnableUNICODE(1);                         // Activate unicode translation for SDL key events.
  SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);  // Enable the key repeats for CEGUI.

  // Finally, return success.
  return (dNO_ERROR);
}


// =============================================================================
// GUI::InitOpenGL
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::InitOpenGL(void)
{
  // Configure OpenGL to host our SDL surface and CEGUI.
  glEnable(GL_CULL_FACE);                       // Enable the culling of polygons based on their winding in window coordinates.
  glDisable(GL_FOG);                            // Disable the blending of a fog color into the post-texturing color.
  glClearColor(0.0f,0.0f,0.0f,1.0f);            // Specify clear values for the color buffers.
  glViewport(0,0, 800,600);                     // Set the OpenGL view port.

  glMatrixMode(GL_PROJECTION);                  // TODO: comment
  glLoadIdentity();                             // TODO: comment
  gluPerspective(45.0, 800.0/600.0, 0.1,100.0); // TODO: comment
  glMatrixMode(GL_MODELVIEW);                   // TODO: comment
  glLoadIdentity();                             // TODO: comment

  // Finally, return success.
  return (dNO_ERROR);
}


// =============================================================================
// GUI::InitCEGUI
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::InitCEGUI(void)
{
  // Connect CEGUI up with the OpenGL renderer.
  CEGUI::OpenGLRenderer::bootstrapSystem();

  // Initialize the resource provider.
  CreateCEGUIResourceProvider(); // TODO: error check

  // Create (load) the TaharezLook scheme file (this auto-loads the
  // TaharezLook looknfeel and imageset files).
  CEGUI::SchemeManager::getSingleton().create("TaharezLook.scheme");

  // Create (load) a font.  The first font loaded automatically becomes the
  // default font, but note that the scheme might have already loaded a font,
  // so there may already be a default set - if we want the "Commonweath-10"
  // font to definitely be the default, we should set the default explicitly
  // afterwards.
  m_pFont = &(CEGUI::FontManager::getSingleton().create("DejaVuSans-10.font"));

/*
  //System::getSingleton().setDefaultFont( "DejaVuSans-10" ); TODO: something??
  // Load the default font. TODO: load during the init stuff...
  m_pFont = &FontManager::getSingleton().create("DejaVuSans-10.font");
  */


  CEGUI::System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow");
  //System::getSingleton().setDefaultToolTip( "TaharezLook/Tooltip" );

  // TODO: comment
  CreateCEGUIRoot();

  // Finally, return success.
  return (dNO_ERROR);
}


// =============================================================================
// GUI::CreateCEGUIResourceProvider
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::CreateCEGUIResourceProvider(void)
{
  // Initialize the required directories for the DefaultResourceProvider.
  CEGUI::DefaultResourceProvider *pRp =
      static_cast<CEGUI::DefaultResourceProvider*> (CEGUI::System::getSingleton().getResourceProvider());

  // Set the resource group directory paths.
  pRp->setResourceGroupDirectory("schemes", "./datafiles/schemes/");
  pRp->setResourceGroupDirectory("imagesets", "./datafiles/imagesets/");
  pRp->setResourceGroupDirectory("fonts", "./datafiles/fonts/");
  pRp->setResourceGroupDirectory("layouts", "./datafiles/layouts/");
  pRp->setResourceGroupDirectory("looknfeels", "./datafiles/looknfeel/");
  pRp->setResourceGroupDirectory("lua_scripts", "./datafiles/lua_scripts/");

  // This is only needed when using Xerces and to specify the schemas location.
  pRp->setResourceGroupDirectory("schemas", "./datafiles/xml_schemas/");

  // Set the default resource groups to be used.
  CEGUI::Imageset::setDefaultResourceGroup("imagesets");
  CEGUI::Font::setDefaultResourceGroup("fonts");
  CEGUI::Scheme::setDefaultResourceGroup("schemes");
  CEGUI::WidgetLookManager::setDefaultResourceGroup("looknfeels");
  CEGUI::WindowManager::setDefaultResourceGroup("layouts");
  CEGUI::ScriptModule::setDefaultResourceGroup("lua_scripts");

  // Setup default group for validation schemas.
  CEGUI::XMLParser* pParser = CEGUI::System::getSingleton().getXMLParser();
  if (pParser->isPropertyPresent("SchemaDefaultResourceGroup"))
    { pParser->setProperty("SchemaDefaultResourceGroup", "schemas"); }

  // Finally, return success.
  return (dNO_ERROR);
}


// =============================================================================
// GUI::CreateCEGUIRoot
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::CreateCEGUIRoot(void)
{
  using namespace CEGUI;

  // Grab a reference to the window manager.
  m_pWm = WindowManager::getSingletonPtr();
  if (m_pWm == NULL) { /* TODO: fault and shutdown */ }

  // Create the root window.
  m_pRoot = m_pWm->createWindow("DefaultWindow", "root");
  if (m_pRoot == NULL) { /* TODO: fault and shutdown */ }

  // Set the active GUI sheet (root) window.
  System::getSingleton().setGUISheet(m_pRoot);

  // Return success.
  return (dNO_ERROR);
}


// =============================================================================
// GUI::NewWindowConsole
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::NewWindowConsole(CEGUI::Window *pParent)
{
  using namespace CEGUI;
  Window *pWindow;
  UDim MenuBarBottom(0, m_pFont->getLineSpacing(12));

  // If no parent was provided, we will attach it to the root.
  if (pParent == NULL) { pParent = m_pRoot; }

  // Create the window.
  pWindow = m_pWm->createWindow("TaharezLook/FrameWindow");
  if (pWindow == NULL) { /* TODO: error */ }

  // Configure the menu bar as needed.
  pWindow->setText("Console");
  pWindow->setAlwaysOnTop(true);      // Keep it on top.
//  pWindow->setModalState(true);
//  pWindow->setAlpha(0.5f);

  pWindow->setArea(UDim(0,0), UDim(0.80f,0), UDim(1,0), UDim(0.20f,0)); // Set the size.

//  void setArea(const UDim& xpos, const UDim& ypos, const UDim& width, const UDim& height);
//  UDim(float scale, float offset) : d_scale(scale), d_offset(offset) {}

  // TODO: clean below the line ----------------------------

//  // position a quarter of the way in from the top-left of parent.
//  pWindow->setPosition( UVector2( UDim( 0.25f, 0 ), UDim( 0.25f, 0 ) ) );
//
//  // set size to be half the size of the parent
//  pWindow->setSize( UVector2( UDim( 0.5f, 0 ), UDim( 0.5f, 0 ) ) );


  pParent->addChildWindow(pWindow);   // Attach it to the parent.
}


// =============================================================================
// GUI::NewWindowAbout
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::NewWindowAbout(CEGUI::Window *pParent)
{
  using namespace CEGUI;
  Window *pWindow;

  // If no parent was provided, we will attach it to the root.
  if (pParent == NULL) { pParent = m_pRoot; }

  // Create the window.
  pWindow = m_pWm->createWindow("TaharezLook/FrameWindow");
  if (pWindow == NULL) { /* TODO: error */ }

  // Configure the menu bar as needed.
  pWindow->setText("About");
  pWindow->setAlwaysOnTop(true);      // Keep it on top.
  pWindow->setModalState(true);
  pWindow->setAlpha(0.5f);

  // TODO: clean below the line ----------------------------

  // position a quarter of the way in from the top-left of parent.
  pWindow->setPosition( UVector2( UDim( 0.25f, 0 ), UDim( 0.25f, 0 ) ) );

  // set size to be half the size of the parent
  pWindow->setSize( UVector2( UDim( 0.5f, 0 ), UDim( 0.5f, 0 ) ) );


  pParent->addChildWindow(pWindow);   // Attach it to the parent.








//  Window* myRoot =  wmgr.getWindow("root");
//
//  FrameWindow* fWnd = static_cast<FrameWindow*>(
//  wmgr.createWindow( "TaharezLook/FrameWindow", "testWindow" ));
//
//  myRoot->addChildWindow( fWnd );
//
//  // position a quarter of the way in from the top-left of parent.
//  fWnd->setPosition( UVector2( UDim( 0.25f, 0 ), UDim( 0.25f, 0 ) ) );
//
//  // set size to be half the size of the parent
//  fWnd->setSize( UVector2( UDim( 0.5f, 0 ), UDim( 0.5f, 0 ) ) );
//
//  fWnd->setText( "Hello World!" );
}


// =============================================================================
// GUI::NewMenuMain
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::NewMenuMain(CEGUI::Window *pParent)
{
  using namespace CEGUI;
  Window *pMenuBar;
//  Window *pMenuItem;
//  Window *pItem;
//  Window *pPopup;
  UDim MenuBarBottom(0, m_pFont->getLineSpacing(2));

  // If no parent was provided, we will attach it to the root.
  if (pParent == NULL) { pParent = m_pRoot; }

  // Create the menu bar.
  pMenuBar = m_pWm->createWindow("TaharezLook/Menubar");             // Create the menu.
  if (pMenuBar == NULL) { /* TODO: error */ }

  // Configure the menu bar as needed.
  pMenuBar->setArea(UDim(0,0), UDim(0,0), UDim(1,0), MenuBarBottom); // Set the size.
  pMenuBar->setAlwaysOnTop(true);                                    // Keep it on top.
  pParent->addChildWindow(pMenuBar);                                 // Attach it to the parent.

  // Add the menu items to the menu bar.
  NewMenuItemFile(pMenuBar); // [File]
  NewMenuItemHelp(pMenuBar); // [Help]

//  // Add the [File] menu item.
//  Window* file = m_pWm->createWindow("TaharezLook/MenuItem");
//  file->setText("File");
//  pMenuBar->addChildWindow(file);
//
//  // file popup
//  Window* popup = m_pWm->createWindow("TaharezLook/PopupMenu");
//  file->addChildWindow(popup);
//
//  // quit item in file menu
//  Window* item = m_pWm->createWindow("TaharezLook/MenuItem");
//  item->setText("Quit");
//  //item->subscribeEvent("Clicked", Event::Subscriber(&ScrollablePaneSample::fileQuit, this));
//  item->subscribeEvent("Clicked", Event::Subscriber(&GUI::fileQuit));
//  popup->addChildWindow(item);

/*
  // demo menu item
  Window* demo = m_pWm->createWindow("TaharezLook/MenuItem");
  demo->setText("Demo");
  pMenuBar->addChildWindow(demo);

  // demo popup
  popup = m_pWm->createWindow("TaharezLook/PopupMenu");
  demo->addChildWindow(popup);

  // demo -> new window
  item = m_pWm->createWindow("TaharezLook/MenuItem");
  item->setText("New dialog");
  item->setTooltipText("Hotkey: Space");
//  item->subscribeEvent("Clicked", Event::Subscriber(&ScrollablePaneSample::demoNewDialog, this));
  popup->addChildWindow(item);
*/


//  // TODO: error checking?

//  using namespace CEGUI;
//  WindowManager& wmgr = WindowManager::getSingleton();
//
//  // If no parent was provided, we will attach it to the root.
//  if (pWindow == NULL) { pWindow = wmgr.getWindow("root"); }
//
//
//  FrameWindow* fWnd = static_cast<FrameWindow*>(
//  wmgr.createWindow( "TaharezLook/FrameWindow", "Main" ));
//
//  pWindow->addChildWindow( fWnd );
//
//  // position a quarter of the way in from the top-left of parent.
//  fWnd->setPosition( UVector2( UDim( 0.25f, 0 ), UDim( 0.25f, 0 ) ) );
//
//  // set size to be half the size of the parent
//  fWnd->setSize( UVector2( UDim( 0.5f, 0 ), UDim( 0.5f, 0 ) ) );
//
//  fWnd->setText( "Hello World!" );

}


// =============================================================================
// GUI::NewMenuFile
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::NewMenuItemFile(CEGUI::Window *pParent)
{
  using namespace CEGUI;
  Window *pMenu, *pPopup, *pItem;

  // Validate our arguments.
  if (pParent == NULL) { /* TODO: error */ }

  // Create the menu item.
  pMenu = m_pWm->createWindow("TaharezLook/MenuItem");
  pMenu->setText("File");         // Set the displayed text.
  pParent->addChildWindow(pMenu); // Attach to the parent.

  // Create the menu popup.
  pPopup = m_pWm->createWindow("TaharezLook/PopupMenu");
  pMenu->addChildWindow(pPopup);  // Attach the popup to the menu.

  // "Quit" item in the menu.
  pItem = m_pWm->createWindow("TaharezLook/MenuItem");
  pItem->setText("Quit");         // Set the displayed text.
  //item->subscribeEvent("Clicked", Event::Subscriber(&ScrollablePaneSample::fileQuit, this));
  pItem->subscribeEvent("Clicked", Event::Subscriber(&GUI::fileQuit));
  pPopup->addChildWindow(pItem);  // Attach the item to the popup.
}


// =============================================================================
// GUI::NewMenuHelp
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GUI::NewMenuItemHelp(CEGUI::Window *pParent)
{
  using namespace CEGUI;
  Window *pMenu, *pPopup, *pItem;

  // Validate our arguments.
  if (pParent == NULL) { /* TODO: error */ }

  // Create the menu item.
  pMenu = m_pWm->createWindow("TaharezLook/MenuItem");
  pMenu->setText("Help");         // Set the displayed text.
  pParent->addChildWindow(pMenu); // Attach to the parent.

  // Create the menu popup.
  pPopup = m_pWm->createWindow("TaharezLook/PopupMenu");
  pMenu->addChildWindow(pPopup);  // Attach the popup to the menu.

  // "About" item in the menu.
  pItem = m_pWm->createWindow("TaharezLook/MenuItem");
  pItem->setText("About");         // Set the displayed text.
  pItem->subscribeEvent("Clicked", Event::Subscriber(&GUI::fileAbout));
  pPopup->addChildWindow(pItem);  // Attach the item to the popup.
}




// quit menu item handler
bool GUI::fileAbout(const CEGUI::EventArgs&)
{
//    d_sampleApp->setQuitting(true);
  NewWindowAbout(m_pRoot);

  puts("About");
    return true;
}

// quit menu item handler
bool GUI::fileQuit(const CEGUI::EventArgs&)
{
//    d_sampleApp->setQuitting(true);
  puts("Quit");
    return true;
}













// =============================================================================
// _UI_DisplayTask
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
// -----------------------------------------------------------------------------
int GUI::DisplayTask(void* Data)
{
  static SDL_Rect Loc;
  static SDL_Surface* pImage = NULL;


  if (pImage == NULL)
  {
    // Create our image.
    pImage = SDL_LoadBMP("hello.bmp");
    // Initialize the location.
    Loc.x = 0;
    Loc.y = 0;
    Loc.w = 100;
    Loc.h = 63;
  }

  if (pImage == NULL) return -1;


//  while (IsRunning == eTRUE)
//  while (1)
  {
    // ROSO: something.
    SDL_BlitSurface(pImage, NULL, m_pSurface, &Loc);

    // Update Screen
//    SDL_Flip(m_pSurface);

    // Pause
//    SDL_Delay(100);

    // Advance the location.
    if (++(Loc.x) > 640) Loc.x = 0;
    if (++(Loc.y) > 480) Loc.y = 0;
  }

  // Finally, return success.
  //return (dNO_ERROR);
  return 0;
}

